<?php
require_once("EKElement.php");
require_once("EKElement.php");
require_once("EKDocument.php");
require_once("EKParagraphRelationship.php");
require_once("EKTalk.php");

class EKParagraph extends EKElement{
	private $id;
	private $type;
	private $enabled;
	private $status;
	
	private $updateTime;
	private $ownerId;
	private $prId;
	private $authorId;
	private $content;
	
	private $refs;
	private $internalLinkIds;
	private $talkIds;
	private $ratingIds;
	
	private $ratingAValue;
	private $ratingAWeight;
	private $ratingBValue;
	private $ratingBWeight;
	
	//Paragraph constructor
	function __construct($id)
	{	
		$this->id = $id;
		$node = EKElement::getElementXmlNode($id, "EKParagraph");
		
		if(!isset($node) || $node->getAttribute("enabled")!="true")
		{
			return false;
		}
		
		$this->enabled = $node->getAttribute("enabled");
		$this->status = $node->getAttribute("status");
		$this->type = $node->getAttribute("type");
		$this->ratingAValue = $node->getAttribute("ratingAValue");
		$this->ratingAWeight = $node->getAttribute("ratingAWeight");
		$this->ratingBValue = $node->getAttribute("ratingBValue");
		$this->ratingBWeight = $node->getAttribute("ratingBWeight");
		
		$this->ownerId = $node->getElementsByTagName("ownerId")->item(0)->nodeValue;
		$this->prId = $node->getElementsByTagName("prId")->item(0)->nodeValue;
		$this->authorId = $node->getElementsByTagName("authorId")->item(0)->nodeValue;
		$this->updateTime = $node->getElementsByTagName("updateTime")->item(0)->nodeValue;
		$this->content = $node->getElementsByTagName("content")->item(0)->nodeValue;
		
		$refSet = $node->getElementsByTagName("ref");
		foreach ($refSet as $refInstance) {
	        $this->refs[] = $refInstance->nodeValue;
		}
		
		$internalLinkSet = $node->getElementsByTagName("internalLinkId");
		foreach ($internalLinkSet as $internalLinkInstance) {
	        $this->internalLinkIds[] = $internalLinkInstance->nodeValue;
		}
		
		$talkIdSet = $node->getElementsByTagName("talkId");
		foreach ($talkIdSet as $talkIdInstance) {
	        $this->talkIds[] = $talkIdInstance->nodeValue;
		}
		
		$ratingIdSet = $node->getElementsByTagName("ratingId");
		foreach ($ratingIdSet as $ratingIdInstance) {
	        $this->ratingIds[] = $ratingIdInstance->nodeValue;
		}
	}
	
	//get the xml node by talkId
	static function getPGXmlNode($id){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$node = $doc->getElementById($id);
		return $node;
	}
	
	# Get rating_A_value by id
	static function getRatingAValueById($id){
		$node = EKParagraph::getPGXmlNode($id);
		return $node->getAttribute("ratingAValue");
	}
	# Get rating_A_weight by id
	static function getRatingAWeightById($id){
		$node = EKParagraph::getPGXmlNode($id);
		return $node->getAttribute("ratingAWeight");
	}
	# Get rating_B_value by id
	static function getRatingBValueById($id){
		$node = EKParagraph::getPGXmlNode($id);
		return $node->getAttribute("ratingBValue");
	}
	# Get rating_B_weight by id
	static function getRatingBWeightById($id){
		$node = EKParagraph::getPGXmlNode($id);
		return $node->getAttribute("ratingBWeight");
	}
	function getContent(){
		return $this->content;
	}
	
	function getUpdateTime(){
		return date("Y/m/d[H:i:s]",$this->updateTime);
	}
	
	function getStatus(){
		return $this->status;
	}
	
	function getRefs(){
		return $this->refs;
	}
	
	function getInternalLinkIds(){
		return $this->internalLinkIds;
	}
	
	function getTalkIds(){
		return $this->talkIds;
	}
	
	function getRatingAValue(){
		return $this->ratingAValue;
	}
	
	function getRatingBValue(){
		return $this->ratingBValue;
	}
	
	function getAutherId(){
		return $this->authorId;
	}
	
	function getOwnerId(){
		return $this->ownerId;
	}
	
	static function createNewParagraphNode($ownerId,$prId, $paragraph_r){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$PRoot = $doc->getElementsByTagName("paragraphRoot")->item(0);
		
		# Paragraph
		$paragraph = $doc->createElement("paragraph");
		
		$newId = EKStatistics::getParagraphLastId();
		$paragraph->setAttribute("id", $newId);
		$paragraph->setAttribute("type", "text");
		$paragraph->setAttribute("enabled", "true");
		$paragraph->setAttribute("status", "pending");
		$paragraph->setAttribute("ratingAValue", 0);
		$paragraph->setAttribute("ratingAWeight", 1);
		$paragraph->setAttribute("ratingBValue", 0);
		$paragraph->setAttribute("ratingBWeight", 1);
		
		
		EKParagraph::giveNewTextNode($doc, "ownerId", $ownerId, $paragraph);
		EKParagraph::giveNewTextNode($doc, "prId", $prId, $paragraph);
		EKParagraph::giveNewTextNode($doc, "authorId", $_SESSION["userid"], $paragraph);
		EKParagraph::giveNewTextNode($doc, "updateTime", time(), $paragraph);
		EKParagraph::giveNewTextNode($doc, "content", $paragraph_r[0], $paragraph);
   		
   		# Refs
   		if(count($paragraph_r[1])!=0)
   		{foreach($paragraph_r[1] as $a){
   			EKParagraph::giveNewTextNode($doc, "ref",$a, $paragraph);
	   	}}
	   		
   		# Internal Link Ids
		if(count($paragraph_r[2])!=0)
		{foreach($paragraph_r[2] as $a){
	   		EKParagraph::giveNewTextNode($doc, "internalLinkId",$a, $paragraph);
	   	}}
		
		$PRoot->appendChild($paragraph);
		$doc->save($xmlfile);
		
		# User<->Element
		EKUser::insertRecord($_SESSION['userid'],"p",$newId);
			
		# If paragraphs are created during document creating, DO NOT record events
		# $event = new EKEvent($_SESSION['userid'],"create","p",$newId);
		# $event->save();
		return $newId;
	}
	
	static function updateParagraphNode($id, $myParagraph){
		$p = new EKParagraph($id);
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$root = $doc->getElementsByTagName("paragraphRoot")->item(0);
		
		if(!$p)
		{
			return false;
		}
		$ownerId = $p->getOwnerId();	
		$prId = $p->prId;
		if($p->getAutherId() == $_SESSION["userid"])
		{
			# this means modify, so we need to reserve some information
			# to reserve:
			#  1. id
			#  2. type
			#  3. ratingAValue
			#  4. ratingAWeight
			#  5. ratingBValue
			#  6. ratingBWeight
			#  7. ownerId & prId (already reserved)
			#  8. talkId (if any)
			#  9. ratingId (if any)
			#  10. oldStatus
			$newId = $id;
			$type = $p->type;
			$ratingAValue = $p->ratingAValue;
			$ratingAWeight = $p->ratingAWeight;
			$ratingBValue = $p->ratingBValue;
			$ratingBWeight = $p->ratingBWeight;
			$ratingIds = $p->ratingIds;
			$talkIds = $p->talkIds;
			$oldStatus = $p->status;
			$node = $doc->getElementById($id);
			$root->removeChild($node);
		}else{
			$newId = EKStatistics::getParagraphLastId();
			$type = "text";
			$ratingAValue = "0";
			$ratingAWeight = "1";
			$ratingBValue = "0";
			$ratingBWeight = "1";
			$ratingIds = array();
			$talkIds = array();
		}
			
		# to update:
		#  1. enabled
		#  2. status (should compare)
		#  3. authorId  
		#  4. updateTime
		#  5. content
		#  6. ref (if any)
		#  7. internalLinkId (if any)
		$enabled = "true";
		$status = "pending";
		$authorId = $_SESSION["userid"];
		$updateTime = time();
		$content = $myParagraph[0];
		$refs=  $myParagraph[1];
		$internalLinkIds = $myParagraph[2];
		
		# Paragraph
		$paragraph = $doc->createElement("paragraph");
		
		$paragraph->setAttribute("id", $newId);
		$paragraph->setAttribute("type", $type);
		$paragraph->setAttribute("enabled", $enabled);
		$paragraph->setAttribute("status", $status);
		$paragraph->setAttribute("ratingAValue", $ratingAValue);
		$paragraph->setAttribute("ratingAWeight", $ratingAWeight);
		$paragraph->setAttribute("ratingBValue", $ratingBValue);
		$paragraph->setAttribute("ratingBWeight", $ratingBWeight);
		EKParagraph::giveNewTextNode($doc, "ownerId", $ownerId, $paragraph);
		EKParagraph::giveNewTextNode($doc, "prId", $prId, $paragraph);
		EKParagraph::giveNewTextNode($doc, "authorId", $authorId, $paragraph);
		EKParagraph::giveNewTextNode($doc, "updateTime", $updateTime, $paragraph);
		EKParagraph::giveNewTextNode($doc, "content", $content, $paragraph);
		
		if(count($refs)>0)
		{foreach($refs as $a){
		 	EKParagraph::giveNewTextNode($doc, "ref", $a, $paragraph);
		}}
		if(count($internalLinkIds)>0)
	   	{foreach($internalLinkIds as $a){
	   		EKParagraph::giveNewTextNode($doc, "internalLinkId", $a, $paragraph);
	   	}}
		if(count($talkIds)>0)
	   	{foreach($talkIds as $a){
	   		EKParagraph::giveNewTextNode($doc, "talkId", $a, $paragraph);
	   	}}
	   	if(count($ratingIds)>0)
	   	{foreach($ratingIds as $a){
	   		EKParagraph::giveNewTextNode($doc, "ratingId", $a, $paragraph);
	   	}}
	   	
		$root->appendChild($paragraph);
		$doc->save($xmlfile);
		
		if($p->getAutherId() != $_SESSION["userid"])
		{
			# User<->Element
			EKUser::insertRecord($_SESSION['userid'],"p",$id);
		
			# Events
			$event = new EKEvent($_SESSION['userid'],"create","p",$id);
			$event->save();
			
			# also need to add to its owner
			$xmlfile = SERVERLOCATION."data/EKParagraphRelationship.xml";
			$doc = DOMDocument::load($xmlfile);
			$doc->validate();
			$node = $doc->getElementById($prId);
			EKParagraph::giveNewTextNode($doc, "paragraphId", $newId, $node);
			$doc->save($xmlfile);
		}else if($oldStatus == "approved")
		{
			# so it is also disapproving event
			EKDocument::checkAllDisapproved($ownerId);
			
			# Events
			$event = new EKEvent($_SESSION['userid'],"disapprove","p",$id);
			$event->save();
		}
		
		return $newId;
	}
	
	# Delete current node, $quick=true means it is deleted with the document
	static function deleteParagraphNode($id, $quick = false){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$documentRoot = $doc->getElementsByTagName("paragraphRoot")->item(0);
		$thisDoc = $doc->getElementById($id);

		$p = new EKParagraph($id);
		
		
		if(!$quick)
		{
			$message[] = "normal";
			$message[] = "Paragraph Id: ". $id ." deleted.";
			$subversion = EKParagraphRelationship::getParagraphIdsById($p->prId);
			if(count($subversion)==1)
			{
				$a = EKParagraphRelationship::deletePRNode($p->prId);
				if($a)
				# the message of deleting document
					return $a;
				else
				# just deleting paragraph relationship
					return $message; 
			}
			
			# delete the paragraphId referred to it in Paragraph Relationship
			EKElement::deleteRefIdById($p->prId, $id, "EKParagraphRelationship", "paragraphId");
			
			# add the delete event to event
			$event = new EKEvent($p->authorId, "delete", "p", $id);
			$event->save();
		}
			
		# handling to the internal link referred to it:
		# reserve it now but delete it when loaded!
			
		# delete the rating and talk referred to it
		if(count($p->ratingIds)>0){
		foreach($p->ratingIds as $a){
			EKRating::deleteRatingNode($a);
		}}
		if(count($p->talkIds)>0){
		foreach($p->talkIds as $a){
			EKTalk::deleteTalkNode($a);
		}}
			
		# delete the relationship with user in the database
		EKUser::delRecord($p->authorId, "p", $id);
			
		$documentRoot->removeChild($thisDoc);
		EKStatistics::decParagraphSumNum();
		$doc->save($xmlfile);
		
		return $message;

	}
	
	# Update internal link, del the non-exist internal link node
	static function upadteInternalLinkById($id){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$node = $doc->getElementById($id);
		$internalLinks = $node->getElementsByTagName("internalLink");
		foreach ($internalLinks as $internalLink) {
	        if(!EKDocument::testExist($internalLink->nodeValue)){
	        	$node->removeChild($internalLink);
	        }
		}
		$doc->save($xmlfile);
	}
	
	# Get ownerId by id
	static function getOwnerIdById($id){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$node = $doc->getElementById($id);
		return $node->getElementsByTagName("ownerId")->item(0)->nodeValue;
	}
	
	# do not check the user session
	# so the session should be checked before it is called
	static function administrate($id, $action, $fromOwner = false){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$thisDoc = $doc->getElementById($id);
		if(!EKElement::isAdminPass($action, $thisDoc->getAttribute("status"))
		|| $thisDoc->getAttribute("enabled") == "false" )
		{
			return "The action '".$action."' on paragraph id = ".$id." is not permitted!";
		}
		
		switch($action)
		{
			case "approve":
				return EKParagraph::approveParagraphNode($id);;
			case "deny":
				return EKParagraph::denyParagraphNode($id);
			default:
				return "The action '".$action."' on paragraph id = ".$id." is not permitted!";
		}
	}
	
	static function approveParagraphNode($id){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$thisDoc = $doc->getElementById($id);

		$p = new EKParagraph($id);
		
		$subversion = EKParagraphRelationship::getParagraphIdsById($p->prId);
		foreach($subversion as $a){
			 EKParagraph::disapproveParagraphNode($doc->getElementById($a), $a);
		}
		
		$thisDoc->setAttribute("status", "approved");
		$doc->save($xmlfile);
		
		if(!EKDocument::checkAllApproved($p->getOwnerId()))
		{
			# add the approve event to event
			$event = new EKEvent($p->authorId, "approve", "p", $id);
			$event->save();
			return "The action 'approve' on paragraph id = ".$id." performed.";
		}
		
		return "The action 'approve' on document id = ".$p->getOwnerId()." performed.";
	}
	
	private static function disapproveParagraphNode($node, $id)
	{
		if($node->getAttribute("status") != "approved")
			return;
		
		$node->setAttribute("status", "pending");
		$authorId = $node->getElementsByTagName("authorId")->item(0)->nodeValue;
		$event = new EKEvent($authorId, "disapprove", "p", $id);
		$event->save();	
	}
	
	# Deny current node, $quick=true means it is deleted with the document
	static function denyParagraphNode($id){
		$xmlfile = SERVERLOCATION."data/EKParagraph.xml";
		$doc = DOMDocument::load($xmlfile);
		$doc->validate();
		$documentRoot = $doc->getElementsByTagName("paragraphRoot")->item(0);
		$thisDoc = $doc->getElementById($id);

		$p = new EKParagraph($id);

		$message = $p->getOwnerId();
		
		$subversion = EKParagraphRelationship::getParagraphIdsById($p->prId);
		if(count($subversion)==1)
		{
			$a = EKParagraphRelationship::denyPRNode($p->prId);
			if($a)
			# the message of deleting document
				return $a;
			else
			# just deleting paragraph relationship
				return $message; 
		}
		
		# delete the paragraphId referred to it in Paragraph Relationship
		EKElement::deleteRefIdById($p->prId, $id, "EKParagraphRelationship", "paragraphId");
		
		# add the delete event to event
		$event = new EKEvent($p->authorId, "deny", "p", $id);
		$event->save();
			
		# handling to the internal link referred to it:
		# reserve it now but delete it when loaded!
			
		# delete the rating and talk referred to it
		if(count($p->ratingIds)>0){
		foreach($p->ratingIds as $a){
			EKRating::deleteRatingNode($a);
		}}
		if(count($p->talkIds)>0){
		foreach($p->talkIds as $a){
			EKTalk::deleteTalkNode($a);
		}}
			
		# delete the relationship with user in the database
		EKUser::delRecord($p->authorId, "p", $id);
			
		$documentRoot->removeChild($thisDoc);
		EKStatistics::decParagraphSumNum();
		$doc->save($xmlfile);
		
		return $message;
	}

}
?>